﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Unity;
using SkeletonNET.Crud.Repository;
using SkeletonNET.Base.Crud.CrudManager;
using SkeletonNET.Base.Crud.UnitOfWork;
using System.Diagnostics;
using System.Linq.Expressions;

namespace SkeletonNET.Live.Tests
{
    [TestClass]
    public class RepositoryTests
    {
        [TestInitialize]
        public void Initialize()
        {
            var container = new UnityContainer();
            ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));

            // Setup the unity container
            container
                .RegisterType(typeof(IRepository<>), typeof(Repository<>))
                .RegisterType(typeof(ICrudManager<>), typeof(CrudManager<>))
                .RegisterType<IUnitOfWork, TestModelContainer>();

            GenerateData();
        }

        private static readonly Expression<Func<IRepository<TestEntity>, int, TestEntity>> getById =
            (repo, id) => repo.GetQuery().Where(x => x.Id == id).FirstOrDefault();
        private static Func<IRepository<TestEntity>, int, TestEntity> getByIdCompiled = getById.Compile();

        [TestMethod]
        public void TestMethod1()
        {
            var testRepo = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();

            Stopwatch watch = Stopwatch.StartNew();

            // Get the data from the database with an uncompiled query
            testRepo.GetQuery().Where(x => x.Id == 100);
            Debug.WriteLine("(1st time) Get with uncompiled query: " + watch.ElapsedMilliseconds.ToString());

            // Get the data from the database with a compiled query
            watch = Stopwatch.StartNew();
            getByIdCompiled(testRepo, 100);
            Debug.WriteLine("(1st time) Get with compiled query: " + watch.ElapsedMilliseconds.ToString());

            // Recreate repo to dump the in memory data
            testRepo = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();

            // Get the data from the database with an uncompiled query
            testRepo.GetQuery().Where(x => x.Id == 100);
            Debug.WriteLine("(2nd time) Get with uncompiled query: " + watch.ElapsedMilliseconds.ToString());

            // Get the data from the database with a compiled query
            watch = Stopwatch.StartNew();
            getByIdCompiled(testRepo, 100);
            Debug.WriteLine("(2nd time) Get with compiled query: " + watch.ElapsedMilliseconds.ToString());
        }

        private void GenerateData()
        {
            // Only generate data if not data exists in the database
            var repo = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();
            if (repo.GetQuery().Count() == 0)
                // Generate data
                for (int i = 0; i < 10000; i++)
                {
                    repo.Insert(new TestEntity() { Name = i.ToString(), Id = i });
                    Debug.WriteLine(string.Format
                        ("Insert record {0}", i.ToString()));
                }

            repo.Save();
        }
    }
}
